#include "mainMemory.h"



char* mmGetPage(int pAddress)
{
	ipt[pAddress].referenceBit = 1;
	return &mainMemory[pAddress*pageSize];
}
/*
void mmSetPage(int pAddress, char* page)
{
	int i;
	for (is = pAddress; i < pageSize + pAddress; ++i)
	{
		mainMemory[i] = page[i-pAddress];
	}
}
*/
void initMainMemory(){
	mainMemory = malloc(pageSize*NumOfPagesInMM*sizeof(char));
	hitCounter = 0;
	faultCounter = 0;
	initHat();
	initIpt();
	isMonitorMode = 1;
}

void killMM()
{
	FREE(mainMemory)
	killHat();
	killIpt();
}

char readByte(int pid,int vAddr){
	int offset = vAddr % pageSize;
	int logicalPage = vAddr / pageSize;
	int pAddr = iptGetPageIndexInMM(pid, logicalPage);
	while (pAddr == -1){
		faultCounter++;
		if (isMonitorMode) printf("page fault occured in process %d, page %d\n",pid,logicalPage);
		//loadPageToMM(pid,logicalPage);
		pMessage_t* message = malloc(sizeof(pMessage_t));
		createMessage(message,NULL,pid,logicalPage,0,NULL,NULL);
		mbox_enqueue(prmMailbox,message);
		readerEnd();
		sem_wait(pcb[pid].waitForPRM);
		readerStart();
		pAddr = iptGetPageIndexInMM(pid, logicalPage);
	}
	//pthread_mutex_lock(&tempmutex);
	hitCounter++;
	if (isMonitorMode) printf("page hit occured in process %d, page %d\n",pid,logicalPage);
	char * page = mmGetPage(pAddr);
	return page[offset];
	//pthread_mutex_unlock(&tempmutex);
}


/**
 * this function will return a new allocated string ,
 * the caller must free this memory
 * */
char * readBytes(int pid, int vAddr, int amount ){
	int endOfMemory = NumOfProcessPages * pageSize - 1;
	char* ans = malloc(amount*sizeof(char));
	int i;
	if (vAddr + amount - 1 > endOfMemory){
			amount = endOfMemory - vAddr;
	}
	sem_wait(&clockSem);
	readerStart();

	for (i = 0; i < amount; i++) {
		ans[i] = readByte(pid,vAddr+i);
	}
	readerEnd();
	sem_post(&deamonSem);
	return ans;
}


void writeByte(int pid, int vAddr, char toWrite )
{
	int offset = vAddr % pageSize;
	int logicalPage = vAddr / pageSize;
	int pAddr = iptGetPageIndexInMM(pid, logicalPage);
	while (pAddr == -1){
		faultCounter++;
		if (isMonitorMode) printf("page fault occured in process %d, page %d\n",pid,logicalPage);
		//loadPageToMM(pid,logicalPage);
		pMessage_t* message = malloc(sizeof(pMessage_t));
		createMessage(message,NULL,pid,logicalPage,0,NULL,NULL);
		mbox_enqueue(prmMailbox,message);
		readerEnd();
		sem_wait(pcb[pid].waitForPRM);
		readerStart();
		pAddr = iptGetPageIndexInMM(pid, logicalPage);
		//sem_post(pcb[pid].waitForPRM);
	}
	hitCounter++;
	if (isMonitorMode) printf("page hit occured in process %d, page %d\n",pid,logicalPage);
	//pthread_mutex_lock(&tempmutex);
	char * page = mmGetPage(pAddr);
	page[offset] = toWrite;
	ipt[pAddr].dirtyBit = 1;
	//pthread_mutex_unlock(&tempmutex);
}
/**
 * will return 1 if succeded
 * will return 0 if trying to write to memory out of bound
 * */
int writeBytes(int pid, int vAddr, int amount, char* toWrite ){

	int i , ans = 1;
	int endOfMemory = NumOfProcessPages * pageSize - 1;
	if (vAddr + amount -1 > endOfMemory){
		ans = 0;
	}
	sem_wait(&clockSem);
	readerStart();
	for (i = 0; i < amount; i++) {
		int addr = vAddr + i;
		if (addr > endOfMemory) break;
		writeByte(pid, addr,toWrite[i]);
	}
	readerEnd();
	sem_post(&deamonSem);
	return ans;
}

void printMM()
{
	int i;
	printf("main mem:\n");
	for (i = 0; i < NumOfPagesInMM*pageSize; ++i)
	{
		printf("%c",mainMemory[i]);
	}
	printf("\n");
}


